/*
 * Status_Manager.cpp
 *
 *  Created on: Mar 7, 2012
 *      Author: ajeffery
 */

#include "Status_Manager.h"
#include "defs.h"
#include "Elevator.h"
#include "FloorRun_Manager.h"

#include <native/task.h>
#include <native/timer.h>
#include <rtdk.h>

#include <stdlib.h>
#include <stdio.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <unistd.h>

extern Elevator *this_lift;
extern FloorRun_Manager *flr_run;

Status_Manager::Status_Manager(Double_Buffer * iBuffer) {

	struct sockaddr_in gui_addr;

	guiSocket = socket(AF_INET, SOCK_STREAM, 0);
	if (guiSocket < 0) {
			perror("ERROR opening guiSocket");
	}

	int flag =1;
	int result =setsockopt(guiSocket, IPPROTO_TCP, TCP_NODELAY,
			(char*) &flag, sizeof(int));
	if (result < 0)
		perror("Failed to remove delay from guiSocket");

	gui_addr.sin_family = AF_INET;
	inet_aton(GUI_ADDR, &gui_addr.sin_addr);
	gui_addr.sin_port = htons(GUI_PORT);

	while (connect(guiSocket,(struct sockaddr *) &gui_addr,sizeof(gui_addr)) < 0)
		rt_task_sleep(SLEEP1S);

	ecinitrep_t initMsg;
	initMsg.type = EC_INIT_MSG;
	initMsg.car = this_lift->getCar_num();
	char * buff = (char *)&initMsg;
	int retval = write(guiSocket, buff, sizeof(ecinitrep_t));
	if (retval < 0)
		perror("ERROR:: guiSocket write Fail");



	buffer = iBuffer;

	flr_run->init_test_socket(guiSocket);

	rt_printf("GUI Connection Found \n");

}

void Status_Manager::read_floor_request(){
	char buff[BUF_SIZE];
	memset(buff, 0, BUF_SIZE);

	while(guiSocket > 0){
		int retval = read(guiSocket, buff, BUF_SIZE);
		if (retval < 0)
			perror("ERROR:: guiSocket read Fail");
		else{
			floor_req_t *new_floor = (floor_req_t*)buff;
			if(new_floor->type == FLOOR_REQUEST){
				if ((new_floor->destfloor >= 0) ||
						(new_floor->destfloor < MAX_FLOORS))
					this_lift->addInternal_call(new_floor->destfloor);
				else
					perror("ERROR Floor (internal):: Request out of Bounds");
			}
			else
				perror("ERROR:: guiSocket Unknown msg");
		}
	}
}

Status_Manager::~Status_Manager() {
	if(guiSocket)
		close(guiSocket);

}

void Status_Manager::update()
{

	if(flr_run->check_reached_dest()){
		int8_t temp_cancels[MAX_FLOORS];
		memset(temp_cancels, 0, MAX_FLOORS);
		temp_cancels[flr_run->get_cur_floor()] = 1;
		this_lift->cancel_hall_calls(temp_cancels);
		this_lift->remove_internal_call(flr_run->get_cur_floor());
	}

	update_destFloor(0);

	this_lift->setCur_floor(flr_run->get_cur_floor());
	this_lift->setDest_floor(flr_run->get_dest());
	this_lift->setStatus(flr_run->get_status());
	this_lift->setDirection(flr_run->get_dir());
}

void Status_Manager::update_destFloor(int inverted_dir){
	int found=0;

	int8_t temp_hallcalls[MAX_FLOORS];
	int8_t temp_interriorcalls[MAX_FLOORS];
	this_lift->getCur_hall_calls(temp_hallcalls);
	this_lift->getInternal_calls(temp_interriorcalls);

	switch(flr_run->get_dir()){
	case(UP):{
		for(int8_t i = flr_run->get_cur_floor() + 1;
				i < MAX_FLOORS;
				i++){
			if (temp_interriorcalls[i] || temp_hallcalls[i]){
				flr_run->set_dest(i);
				found =1;
				break;
			}
		}
		if(!found && !inverted_dir){
			flr_run->set_dir(DOWN);
			update_destFloor(!inverted_dir);
		}
		break;
	}
	case(DOWN):{
		for(int8_t i = flr_run->get_cur_floor() - 1;
				i >= 0;
				i--){
			if (i < 0)
				continue;
			if (temp_interriorcalls[i] || temp_hallcalls[i]){
				flr_run->set_dest(i);
				found =1;
				break;
			}
		}
		if(!found && !inverted_dir){
			flr_run->set_dir(UP);
			update_destFloor(!inverted_dir);
		}
		break;
	}
	}
}
